package com.example.synccenter.identitysource.registry;

import com.example.synccenter.dingtalk.DingTalkClient;
import com.example.synccenter.dingtalk.DingTalkConfig;
import com.example.synccenter.dingtalk.DingTalkIdentitySource;
import com.example.synccenter.entity.IdentitySourceEntity;
import com.example.synccenter.feishu.FeishuClient;
import com.example.synccenter.feishu.FeishuConfig;
import com.example.synccenter.feishu.FeishuIdentitySource;
import com.example.synccenter.identitysource.core.IdentitySource;
import com.example.synccenter.identitysource.core.IdentitySourceClient;
import com.example.synccenter.identitysource.core.IdentitySourceConfig;
import com.example.synccenter.identitysource.core.IdentitySourceEventListener;
import com.example.synccenter.identitysource.processor.DefaultIdentitySourceDeptPostProcessor;
import com.example.synccenter.identitysource.processor.DefaultIdentitySourceEventPostProcessor;
import com.example.synccenter.identitysource.processor.DefaultIdentitySourceUserPostProcessor;
import com.example.synccenter.service.IdentitySourceService;
import com.example.synccenter.task.IdentitySourceSyncTask;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * 身份源Bean注册管理器，负责身份源的动态注册、销毁和同步任务管理。
 * 实现了身份源事件监听器接口，处理身份源的生命周期事件。
 */
@Slf4j
@Component
public class IdentitySourceBeanRegistry implements IdentitySourceEventListener {

    private static final String LOCK_PREFIX = "identity_source_sync:";
    private static final String BEAN_NAME_PREFIX = "identitySource_";
    private static final String TASK_NAME_PREFIX = "identitySourceTask_";
    public static final String FEISHU = "FEISHU";
    public static final String DINGTALK = "DINGTALK";

    private final ApplicationContext applicationContext;
    private final IdentitySourceService identitySourceService;
    private final RedissonClient redissonClient;
    private final ScheduledTaskRegistrar taskRegistrar;
    private final ConcurrentHashMap<String, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
    private final ObjectMapper objectMapper;

    /**
     * 构造方法，初始化时注册所有已启用的身份源
     *
     * @param applicationContext    Spring应用上下文
     * @param identitySourceService 身份源服务
     * @param redissonClient        Redis客户端
     * @param taskRegistrar         任务注册器
     * @param objectMapper          JSON序列化工具
     */
    public IdentitySourceBeanRegistry(ApplicationContext applicationContext,
                                      IdentitySourceService identitySourceService,
                                      RedissonClient redissonClient,
                                      ScheduledTaskRegistrar taskRegistrar,
                                      ObjectMapper objectMapper) {
        this.applicationContext = applicationContext;
        this.identitySourceService = identitySourceService;
        this.redissonClient = redissonClient;
        this.taskRegistrar = taskRegistrar;
        this.objectMapper = objectMapper;

        // 初始化时注册所有启用的身份源
        var enabledSources = identitySourceService.lambdaQuery()
                .eq(IdentitySourceEntity::getEnabled, true)
                .eq(IdentitySourceEntity::getConfigured, true)
                .list();

        log.info("开始初始化身份源，共发现{}个已启用的身份源", enabledSources.size());

        Map<String, Integer> typeStats = new ConcurrentHashMap<>();
        Map<String, Integer> statusStats = new ConcurrentHashMap<>();

        enabledSources.forEach(source -> {
            try {
                register(source);
                // 统计类型
                typeStats.merge(source.getType(), 1, Integer::sum);
                // 统计状态
                statusStats.merge("success", 1, Integer::sum);
            } catch (Exception e) {
                log.error("注册身份源失败: {}, 错误: {}", source.getName(), e.getMessage());
                statusStats.merge("failed", 1, Integer::sum);
            }
        });

        // 输出统计信息
        log.info("身份源初始化完成:总数: {}, 成功: {}, 失败: {}",
                enabledSources.size(),
                statusStats.getOrDefault("success", 0),
                statusStats.getOrDefault("failed", 0));

        // 输出类型分布
        if (!typeStats.isEmpty()) {
            StringBuilder typeInfo = new StringBuilder("身份源分布: ");
            typeStats.forEach((type, count) ->
                    typeInfo.append(type).append("=").append(count).append(", "));
            log.info(typeInfo.substring(0, typeInfo.length() - 2));
        }

        // 输出定时任务信息
        int scheduledTasks = (int) enabledSources.stream()
                .filter(source -> StringUtils.isNotBlank(source.getCron()))
                .count();
        log.info("定时任务: {}个", scheduledTasks);
    }

    /**
     * 注册身份源
     *
     * @param id 身份源ID
     */
    @Override
    public void register(String id) {
        IdentitySourceEntity entity = identitySourceService.getById(id);
        if (entity != null && entity.getEnabled() && entity.getConfigured()) {
            register(entity);
        }
    }

    /**
     * 注册身份源实体
     *
     * @param entity 身份源实体
     */
    public void register(IdentitySourceEntity entity) {
        log.info("开始注册身份源: {}", entity.getName());
        registerIdentitySourceBean(entity);
        if (StringUtils.isNotBlank(entity.getCron())) {
            registerIdentitySourceSyncTask(entity);
        }
        log.info("完成注册身份源: {}", entity.getName());
    }

    /**
     * 销毁身份源
     *
     * @param id 身份源ID
     */
    @Override
    public void destroy(String id) {
        log.info("开始销毁身份源: {}", id);
        destroyIdentitySourceBean(id);
        destroyIdentitySourceSyncTask(id);
        log.info("完成销毁身份源: {}", id);
    }

    /**
     * 手动触发身份源同步
     *
     * @param id 身份源ID
     */
    @Override
    public void sync(String id) {
        IdentitySource identitySource = getIdentitySourceBean(id);
        if (identitySource == null) {
            log.warn("未找到身份源: {}", id);
            return;
        }

        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        log.info("[手动任务]-同步身份源[{}]数据开始", identitySource.getName());

        RLock lock = redissonClient.getLock(LOCK_PREFIX + id);
        boolean locked = false;
        try {
            locked = lock.tryLock(1, TimeUnit.SECONDS);
            if (locked) {
                identitySource.sync(Map.of("triggerType", "MANUAL"));
            } else {
                log.warn("获取同步锁失败，跳过本次同步: {}", identitySource.getName());
            }
        } catch (Exception e) {
            log.error("同步身份源数据失败: {}, 错误: {}", identitySource.getName(), e.getMessage(), e);
        } finally {
            if (locked && lock.isLocked()) {
                lock.unlock();
            }
            stopWatch.stop();
            log.info("[手动任务]-同步身份源[{}]数据结束, 执行时长: {} ms",
                    identitySource.getName(), stopWatch.getTotalTimeMillis());
        }
    }

    /**
     * 注册身份源Bean到Spring容器
     *
     * @param entity 身份源实体
     */
    private void registerIdentitySourceBean(IdentitySourceEntity entity) {
        String beanName = getBeanName(entity.getId());
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) ((ConfigurableApplicationContext) applicationContext).getBeanFactory();

        // 如果已存在，先销毁
        try {
            destroyIdentitySourceBean(entity.getId());
        } catch (NoSuchBeanDefinitionException ignored) {
        }

        try {
            // 创建Bean定义
            BeanDefinitionBuilder builder;
            IdentitySourceClient client;
            IdentitySourceConfig config;

            // 获取处理器
            ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
            DefaultIdentitySourceUserPostProcessor userProcessor = beanFactory.getBean(DefaultIdentitySourceUserPostProcessor.class);
            DefaultIdentitySourceDeptPostProcessor deptProcessor = beanFactory.getBean(DefaultIdentitySourceDeptPostProcessor.class);
            DefaultIdentitySourceEventPostProcessor eventProcessor = beanFactory.getBean(DefaultIdentitySourceEventPostProcessor.class);

            // 根据类型创建不同的身份源实现
            switch (entity.getType()) {
                case DINGTALK:
                    config = objectMapper.readValue(entity.getConfig(), DingTalkConfig.class);
                    config.setId(entity.getId());
                    client = new DingTalkClient((DingTalkConfig) config);
                    builder = BeanDefinitionBuilder.genericBeanDefinition(DingTalkIdentitySource.class);
                    break;
                case FEISHU:
                    config = objectMapper.readValue(entity.getConfig(), FeishuConfig.class);
                    config.setId(entity.getId());
                    client = new FeishuClient((FeishuConfig) config);
                    builder = BeanDefinitionBuilder.genericBeanDefinition(FeishuIdentitySource.class);
                    break;
                default:
                    throw new IllegalArgumentException("不支持的身份源类型: " + entity.getType());
            }

            // 设置构造参数
            builder.addConstructorArgValue(entity.getId());
            builder.addConstructorArgValue(entity.getName());
            builder.addConstructorArgValue(config);
            builder.addConstructorArgValue(client);
            builder.addConstructorArgValue(userProcessor);
            builder.addConstructorArgValue(deptProcessor);
            builder.addConstructorArgValue(eventProcessor);
            builder.setScope(ConfigurableBeanFactory.SCOPE_SINGLETON);

            // 注册Bean
            BeanDefinitionHolder holder = new BeanDefinitionHolder(builder.getBeanDefinition(), beanName);
            BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
            log.info("注册身份源Bean成功: {}", entity.getName());
        } catch (Exception e) {
            log.error("注册身份源Bean失败: {}, 错误: {}", entity.getName(), e.getMessage(), e);
            throw new RuntimeException("注册身份源Bean失败: " + e.getMessage(), e);
        }
    }

    /**
     * 注册身份源同步定时任务
     *
     * @param entity 身份源实体
     */
    private void registerIdentitySourceSyncTask(IdentitySourceEntity entity) {
        String taskId = getTaskId(entity.getId());

        // 如果已存在，先销毁
        destroyIdentitySourceSyncTask(entity.getId());

        try {
            // 创建同步任务
            IdentitySource identitySource = getIdentitySourceBean(entity.getId());
            if (identitySource != null && taskRegistrar.getScheduler() != null) {
                IdentitySourceSyncTask syncTask = new IdentitySourceSyncTask(
                        entity.getId(),
                        entity.getName(),
                        redissonClient,
                        identitySource
                );

                ScheduledFuture<?> future = taskRegistrar.getScheduler().schedule(
                        syncTask,
                        new CronTrigger(entity.getCron())
                );

                scheduledTasks.put(taskId, future);
                log.info("注册身份源定时同步任务成功: {}, cron: {}", entity.getName(), entity.getCron());
            }
        } catch (Exception e) {
            log.error("注册身份源定时同步任务失败: {}, 错误: {}", entity.getName(), e.getMessage(), e);
            throw new RuntimeException("注册身份源定时同步任务失败: " + e.getMessage(), e);
        }
    }

    /**
     * 销毁身份源Bean
     *
     * @param id 身份源ID
     */
    private void destroyIdentitySourceBean(String id) {
        String beanName = getBeanName(id);
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
        if (registry.containsBeanDefinition(beanName)) {
            registry.removeBeanDefinition(beanName);
            log.info("销毁身份源Bean成功: {}", id);
        }
    }

    /**
     * 销毁身份源同步定时任务
     *
     * @param id 身份源ID
     */
    private void destroyIdentitySourceSyncTask(String id) {
        String taskId = getTaskId(id);
        ScheduledFuture<?> future = scheduledTasks.remove(taskId);
        if (future != null) {
            future.cancel(true);
            log.info("销毁身份源定时同步任务成功: {}", id);
        }
    }

    /**
     * 获取身份源实例
     *
     * @param id 身份源ID
     * @return 身份源实例
     */
    public IdentitySource getIdentitySource(String id) {
        return getIdentitySourceBean(id);
    }

    /**
     * 获取身份源Bean
     *
     * @param id 身份源ID
     * @return 身份源Bean实例
     */
    private IdentitySource getIdentitySourceBean(String id) {
        try {
            return (IdentitySource) applicationContext.getBean(getBeanName(id));
        } catch (NoSuchBeanDefinitionException e) {
            return null;
        }
    }

    /**
     * 获取身份源Bean名称
     *
     * @param id 身份源ID
     * @return Bean名称
     */
    private String getBeanName(String id) {
        return BEAN_NAME_PREFIX + id;
    }

    /**
     * 获取身份源同步任务ID
     *
     * @param id 身份源ID
     * @return 任务ID
     */
    private String getTaskId(String id) {
        return TASK_NAME_PREFIX + id;
    }
} 